commonlibsse_ng\re\t/
TESObjectREFR.rs

1mod vtable;
2
3pub use self::vtable::TESObjectREFRVtbl;
4
5use core::ffi::c_void;
6use core::ptr::NonNull;
7use std::collections::HashMap;
8
9use crate::re::BSAnimationGraphEvent::BSAnimationGraphEvent;
10use crate::re::BSHandleRefObject::BSHandleRefObject;
11use crate::re::BSTArray::BSTSmallArray;
12use crate::re::BSTEvent::BSTEventSink;
13use crate::re::ExtraContainerChanges::ExtraContainerChanges;
14use crate::re::ExtraDataList::ExtraDataList;
15use crate::re::IAnimationGraphManagerHolder::IAnimationGraphManagerHolder;
16use crate::re::InventoryChanges::InventoryChanges;
17use crate::re::InventoryEntryData::InventoryEntryData;
18use crate::re::NiAVObject::NiAVObject;
19use crate::re::NiPoint3::NiPoint3;
20use crate::re::NiSmartPointer::NiPointer;
21use crate::re::TESBoundObject::TESBoundObject;
22use crate::re::TESForm::TESForm;
23use crate::re::TESObjectCELL::TESObjectCELL;
24use crate::re::{ObjectHandle, TesWaterForm};
25
26////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
27
28#[repr(C)]
29#[derive(Debug)]
30pub struct OBJ_REFR {
31    pub objectReference: *mut TESBoundObject, // 00
32    pub angle: NiPoint3,                      // 08
33    pub location: NiPoint3,                   // 14
34}
35
36const _: () = assert!(core::mem::size_of::<OBJ_REFR>() == 0x20);
37
38#[derive(Debug)]
39#[repr(C)]
40pub struct LOADED_REF_DATA {
41    pub unk00: BSTSmallArray<*mut c_void>, // handleList?
42    pub current_water_type: *mut TesWaterForm,
43    pub relevant_water_height: f32,
44    pub cached_radius: f32,
45    pub flags: u16,
46    pub underwater_count: i16,
47    pub unk30: u64,
48    pub unk38: u64,
49    pub unk40: u64,
50    pub unk48: u64,
51    pub unk50: u64,
52    pub unk58: u64,
53    pub unk60: u64,
54    pub data_3d: NiPointer<NiAVObject>,
55    pub unk70: *mut c_void, // smart ptr
56}
57
58#[repr(C)]
59#[derive(Debug)]
60pub struct TESObjectREFR {
61    pub __base: TESForm,                              // 00
62    pub __base1: BSHandleRefObject,                   // 20
63    pub __base2: BSTEventSink<BSAnimationGraphEvent>, // 30
64    pub __base3: IAnimationGraphManagerHolder,        // 38
65    pub data: OBJ_REFR,                               // 40
66    pub parentCell: *mut TESObjectCELL,               // 60
67    pub loadedData: *mut LOADED_REF_DATA,             // 68
68    pub extraList: ExtraDataList,                     // 70
69}
70const _: () = assert!(core::mem::size_of::<TESObjectREFR>() == 0x78);
71
72impl crate::re::NiSmartPointer::RefCountable for TESObjectREFR {
73    #[inline]
74    fn inc_ref_count(&self) {
75        self.__base1.inc_ref_count();
76    }
77
78    #[inline]
79    fn dec_ref_count(&mut self) {
80        self.__base1.dec_ref_count();
81    }
82}
83
84type Count = i32;
85pub type InventoryCountMap = HashMap<*mut TESBoundObject, Count>;
86pub type InventoryItemMap = HashMap<*mut TESBoundObject, (Count, Box<InventoryEntryData>)>;
87pub type InventoryDropMap = HashMap<*mut TESBoundObject, (Count, Vec<ObjectHandle>)>;
88
89impl TESObjectREFR {
90    pub fn get_inventory_filter<F>(&self, filter: F, no_init: bool) -> Option<InventoryItemMap>
91    where
92        F: Fn(&TESBoundObject) -> bool,
93    {
94        let inventory_changed = self.get_inventory_changes(no_init)?;
95        let inventory_changed = unsafe { &*inventory_changed };
96
97        let mut inventory = InventoryItemMap::new();
98        for entry in unsafe { inventory_changed.entryList.as_ref()?.iter() } {
99            if entry.is_null() {
100                continue;
101            }
102
103            let entry_ref = unsafe { entry.as_ref()? };
104            let object = entry_ref.object;
105            if filter(unsafe { object.as_ref()? }) {
106                inventory.insert(object, (entry_ref.countDelta, Box::new(entry_ref.clone())));
107            }
108        }
109
110        Some(inventory)
111    }
112
113    // fn get_inventory_counts(&self) -> InventoryCountMap {
114    //     unimplemented!()
115    // }
116
117    pub fn get_inventory_changes(&self, no_init: bool) -> Option<*mut InventoryChanges> {
118        if !self.extraList.has_type(ExtraContainerChanges::EXTRA_DATA_TYPE) {
119            if no_init {
120                return None;
121            };
122
123            if !self.init_inventory_if_required(false) {
124                self.force_init_inventory_changes();
125            }
126        }
127        let x_container = self.extraList.get_by_type_as::<ExtraContainerChanges>()?;
128        Some(unsafe { x_container.as_ref() }.changes)
129    }
130
131    #[inline]
132    pub const fn get_object_reference(&self) -> *mut TESBoundObject {
133        self.data.objectReference
134    }
135
136    /// # Panics
137    /// Returns an error if address resolution fails.
138    #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 15800, ae_id = 16038)]
139    pub fn init_inventory_if_required(&self, ignore_container_extra_data: bool) -> bool {}
140
141    pub fn force_init_inventory_changes(&self) -> *mut InventoryChanges {
142        let changes = self.make_inventory_changes();
143        if !changes.is_null() {
144            let changes = unsafe { &*changes };
145            changes.init_leveled_items();
146            changes.init_from_container_extra();
147            changes.init_scripts();
148        }
149        changes
150    }
151
152    /// # Panics
153    /// If failed to resolve this method's address.
154    pub fn make_inventory_changes(&self) -> *mut InventoryChanges {
155        type SelfSignature = fn(this: *const ()) -> *mut InventoryChanges;
156
157        {
158            static FUNC: std::sync::LazyLock<SelfSignature> = std::sync::LazyLock::new(|| {
159                use crate::rel::ResolvableAddress as _;
160                use crate::rel::id::RelocationID;
161
162                const SE_ID: u64 = 15802;
163                const AE_ID: u64 = 16040;
164
165                let fn_ptr =
166                    RelocationID::new(SE_ID, AE_ID, SE_ID).address().unwrap_or_else(|err| {
167                        #[cfg(feature = "tracing")]
168                        tracing::error!("[Critical Error] Failed to resolve address: {err}");
169                        panic!("Failed to resolve address: {err}")
170                    });
171                unsafe { core::mem::transmute::<NonNull<c_void>, SelfSignature>(fn_ptr) }
172            });
173            FUNC((self as *const Self).cast())
174        }
175    }
176}